export interface AnyObject {
  [x: string]: any;
}

export type Data = string | AnyObject | ArrayBuffer;
export type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'HEAD' | 'OPTIONS' | 'TRACE';
export type DataType = 'json' | 'text' | 'html';
export type ResponseType = 'text' | 'arraybuffer';
export type Callback<T = any> = (result: T) => void;

export interface Request<T> extends Promise<T>, AxiosRequestTask<Request<T>> {}

export interface RequestConstructor extends PromiseConstructor {
  readonly prototype: Request<any>;
  new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Request<T>;
  task: AxiosRequestTask | null;
  aborted: boolean;
  onHeadersReceivedCallback: Callback | null;
  offHeadersReceivedCallback: Callback | null;
  onHeadersReceived(callback: Callback): void;
  offHeadersReceived(callback: Callback): void;
}

export interface AxiosRequestTask<T = void> {
  abort(): T;
  onHeadersReceived(callback: Callback): T;
  offHeadersReceived(callback: Callback): T;
}

export interface AxiosRequestConfig {
  baseURL?: string;
  url?: string;
  data?: Data;
  query?: AnyObject;
  params?: AnyObject;
  header?: any;
  method?: Method;
  timeout?: number;
  dataType?: DataType;
  responseType?: ResponseType;
  sslVerify?: boolean;
  withCredentials?: boolean;
  firstIpv4?: boolean;
  xhr?: (task: AxiosRequestTask, config: AxiosRequestConfig) => void;
  validateStatus?: ((statusCode?: number) => boolean) | null;
  adapter?: (config: AxiosRequestConfig, Request: RequestConstructor) => Promise<any>;
}

export type AxiosConfigType = AxiosRequestConfig | (() => AxiosRequestConfig) | (() => Promise<AxiosRequestConfig>) | undefined;

export interface AxiosCallbackConfig<T = any> extends AxiosRequestConfig {
  success?: Callback<T>;
  fail?: Callback;
  complete?: Callback;
}

export interface AxiosResponse<T = any> {
  data: T;
  statusCode: number;
  header: any;
  config: AxiosRequestConfig;
  message: string;
  cookies: string[];
}

export interface AxiosInterceptorManager<V> {
  use<T = V>(onFulfilled?: (value: V) => T | Promise<T>, onRejected?: (error: any) => any): number;
  eject(id: number): void;
}

export interface AxiosInvoke {
  <T = any, R = AxiosResponse<T>>(config?: AxiosRequestConfig): Request<R>;
  <T = any, R = AxiosResponse<T>>(config?: AxiosCallbackConfig<R>): Request<void>;
  <T = any, R = AxiosResponse<T>>(url?: string, data?: Data, config?: AxiosRequestConfig): Request<R>;
}

export interface AxiosInstance<T extends AxiosConfigType> extends AxiosInvoke {
  get: AxiosInvoke;
  post: AxiosInvoke;
  put: AxiosInvoke;
  delete: AxiosInvoke;
  connect: AxiosInvoke;
  head: AxiosInvoke;
  options: AxiosInvoke;
  trace: AxiosInvoke;
  getURL(config?: AxiosConfigType): Promise<string>;
  readonly defaults: AxiosRequestConfig;
  readonly config: T;
  interceptors: {
    request: AxiosInterceptorManager<AxiosRequestConfig>;
    response: AxiosInterceptorManager<AxiosResponse>;
  };
}

export interface AxiosStatic extends AxiosInstance<undefined> {
  create<T extends AxiosConfigType = undefined>(config?: T): AxiosInstance<T>;
}

declare const Axios: AxiosStatic;

export default Axios;
